package acom.dhy.qigsaw2test.qigsaw

import acom.dhy.qigsaw2test.R
import android.annotation.SuppressLint
import android.app.PendingIntent
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import android.view.ViewGroup
import android.widget.ProgressBar
import android.widget.TextView
import android.widget.Toast
import androidx.activity.result.IntentSenderRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import com.dhy.xintent.XIntent
import com.dhy.xintent.putSerializableExtra
import com.dhy.xintent.readExtraList
import com.google.android.play.core.splitinstall.*
import com.google.android.play.core.splitinstall.model.SplitInstallErrorCode
import com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus
import java.text.DecimalFormat

class QigsawInstallerActivity : AppCompatActivity() {
    private val startIntentSenderForResult = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) {
        if (it.resultCode == RESULT_CANCELED) onFailed()
    }
    private val installManager by lazy { SplitInstallManagerFactory.create(this)!! }
    private var firstStartup = true
    private lateinit var moduleNames: List<String>
    private lateinit var progressBar: ProgressBar
    private lateinit var progressText: TextView
    private var mSessionId = 0
    private var mStatus = 0
    private var startInstallFlag = false
    private val decimalFormat = DecimalFormat("#%")
    private val installStateListener = SplitInstallStateUpdatedListener { state ->
        Log.e(TAG, "SplitInstallStateUpdatedListener error, ${state.errorCode()}: ${state.status()}")
        if (state.moduleNames() == moduleNames) {
            mStatus = state.status()
            when (state.status()) {
                SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION -> onRequiresUserConfirmation(state)
                SplitInstallSessionStatus.CANCELING -> {
                }
                SplitInstallSessionStatus.CANCELED -> {
                }
                SplitInstallSessionStatus.PENDING -> onPending(state)
                SplitInstallSessionStatus.DOWNLOADING -> onDownloading(state)
                SplitInstallSessionStatus.DOWNLOADED -> onDownloaded()
                SplitInstallSessionStatus.INSTALLING -> onInstalling()
                SplitInstallSessionStatus.INSTALLED -> onInstalled()
                SplitInstallSessionStatus.FAILED -> onFailed()
                else -> {
                }
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_qigsaw_installer)
        window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
        moduleNames = readExtraList()
        progressBar = findViewById(R.id.qigsaw_installer_progress)
        progressText = findViewById(R.id.qigsaw_installer_status)
        installManager.registerListener(installStateListener)
    }

    override fun onDestroy() {
        super.onDestroy()
        installManager.unregisterListener(installStateListener)
    }

    override fun onResume() {
        super.onResume()
        if (firstStartup) startInstall()
        firstStartup = false
    }

    private fun startInstall() {
        if (installManager.installedModules.containsAll(moduleNames)) {
            return onInstalled()
        }
        val builder = SplitInstallRequest.newBuilder()
        for (module in moduleNames) {
            builder.addModule(module)
        }
        val request = builder.build()
        installManager.startInstall(request)
            .addOnSuccessListener { integer ->
                mSessionId = integer
                startInstallFlag = true
            }
            .addOnFailureListener { e ->
                startInstallFlag = true
                if (e is SplitInstallException) {
                    Log.e(TAG, "addOnFailureListener error, ${e.errorCode}: ${e.message}")
                    when (e.errorCode) {
                        SplitInstallErrorCode.INCOMPATIBLE_WITH_EXISTING_SESSION -> handleInstallRequestError(getString(R.string.installer_error_incompatible_with_existing_session), false)
                        SplitInstallErrorCode.SERVICE_DIED -> handleInstallRequestError(getString(R.string.installer_error_service_died))
                        SplitInstallErrorCode.NETWORK_ERROR -> handleInstallRequestError(getString(R.string.installer_error_network_error))
                        SplitInstallErrorCode.ACTIVE_SESSIONS_LIMIT_EXCEEDED -> checkForActiveDownloads()
                        SplitInstallErrorCode.INTERNAL_ERROR -> handleInstallRequestError(getString(R.string.installer_error_internal_error))
                        SplitInstallErrorCode.SESSION_NOT_FOUND -> {
                        }
                        SplitInstallErrorCode.INVALID_REQUEST -> handleInstallRequestError(getString(R.string.installer_error_invalid_request))
                        SplitInstallErrorCode.API_NOT_AVAILABLE -> {
                        }
                        SplitInstallErrorCode.MODULE_UNAVAILABLE -> handleInstallRequestError(getString(R.string.installer_error_module_unavailable))
                        SplitInstallErrorCode.ACCESS_DENIED -> handleInstallRequestError(getString(R.string.installer_error_access_denied))
                        else -> {
                        }
                    }
                    onFailed()
                } else {
                    Log.e(TAG, "addOnFailureListener error, ${e.message}")
                }
            }
    }

    private fun handleInstallRequestError(msg: String, finish: Boolean = true) {
        if (!TextUtils.isEmpty(msg)) {
            Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
        }
        if (finish) {
            updateProgressMessage(msg)
            finish()
        }
    }

    private fun checkForActiveDownloads() {
        // Returns a SplitInstallSessionState object for each active session as a List.
        installManager
            .sessionStates
            .addOnCompleteListener { task ->
                if (task.isSuccessful) {
                    for (state in task.result) {
                        if (state.status() == SplitInstallSessionStatus.DOWNLOADING) {
                            installManager.cancelInstall(state.sessionId()).addOnCompleteListener { startInstall() }
                        }
                    }
                }
            }
    }

    private fun onRequiresUserConfirmation(state: SplitInstallSessionState) {
        startIntentSenderForResult.launch(state.resolutionIntent().toIntentSenderRequest())
    }

    private fun onPending(state: SplitInstallSessionState) {
        updateProgressMessage(getString(R.string.installer_pending))
        progressBar.max = state.totalBytesToDownload().toInt()
    }

    @SuppressLint("StringFormatInvalid")
    private fun onDownloading(state: SplitInstallSessionState) {
        progressBar.progress = state.bytesDownloaded().toInt()
        val progress = if (state.bytesDownloaded() == 0L) ""
        else {
            val progress = (state.bytesDownloaded().toFloat() / state.totalBytesToDownload())
            decimalFormat.format(progress)
        }
        println("progress $progress")
        progressText.text = progress
//        updateProgressMessage(progress)
    }

    private fun onDownloaded() {
        updateProgressMessage(getString(R.string.installer_downloaded))
    }

    private fun onInstalling() {
        updateProgressMessage(getString(R.string.installer_installing))
    }

    private fun onInstalled() {
        updateProgressMessage(getString(R.string.installer_installed))
        onInstallOK()

        XIntent.with().apply {
            putSerializableExtra(moduleNames)
            setResult(RESULT_OK, this)
        }

        finish()
    }

    private fun onFailed() {
        setResult(RESULT_CANCELED)
        finish()
    }

    private fun updateProgressMessage(message: String) {
        println("updateProgressMessage $message")
//        progressText.text = message//fixme
    }

    private fun onInstallOK() {}
    override fun onBackPressed() {
        if (mStatus == SplitInstallSessionStatus.UNKNOWN) {
            Log.d(TAG, "Split download is not started!")
            super.onBackPressed()
            return
        }
        if (mStatus == SplitInstallSessionStatus.CANCELING || mStatus == SplitInstallSessionStatus.DOWNLOADED || mStatus == SplitInstallSessionStatus.INSTALLING) {
            // ignore back on these status
            return
        }
        if (!startInstallFlag) {
            return
        }
        if (mSessionId != 0) {
            installManager.cancelInstall(mSessionId).addOnSuccessListener {
                Log.d(TAG, "Cancel task successfully, session id :$mSessionId")
                if (!isFinishing) {
                    finish()
                }
            }.addOnFailureListener {
                Log.d(TAG, "Cancel task failed, session id :$mSessionId")
                if (!isFinishing) {
                    finish()
                }
            }
        } else {
            super.onBackPressed()
        }
    }

    companion object {
        private const val TAG = "QigsawInstaller"
    }

}
fun PendingIntent.toIntentSenderRequest(): IntentSenderRequest {
    return IntentSenderRequest.Builder(this).build()
}